/**
 * Copyright 1996 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 *
 * Note, this is a very old runtime library that I have evolved since 1996. I rarely use it
 * now because the Apache Commons project has made it obsolete.
 */
package self.text;

import java.util.ArrayList;
import java.util.List;

import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternMatcherInput;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;

import self.lang.StringUtils;

public class OroPatternMatcher implements PatternMatcherUtils.PatternMatcher {
	public void acquireMatches(String src, String regExPat, ArrayList matches)
			throws IllegalArgumentException, IllegalStateException {
		matches.clear();
		try {
			try {
				_acquireMatches(src, regExPat, matches,
						Perl5Compiler.MULTILINE_MASK);
			} catch (StackOverflowError err) {
				//        String dumpFile = "";
				//        try {
				//          File dump = File.createTempFile( "oro-stackoverflow", ".txt"
				// );
				//          dumpFile = dump.toString();
				//          FileWriter fw = new FileWriter( dump );
				//          BufferedWriter bw = new BufferedWriter( fw );
				//          try {
				//            bw.write( src );
				//            bw.write( "\nREGEXP=" + regExPat );
				//            bw.flush();
				//          } finally {
				//            bw.close();
				//          }
				//        } catch ( Exception errFw ) {}
				//      	System.err.println( "StackOverflowError on _acquireMatches
				// with REGEX->" + regExPat + ", see file:" + dumpFile );
				System.err
						.println("StackOverflowError on _acquireMatches with REGEX->"
								+ regExPat);
				matches.clear();
				// see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5055
				regExPat = StringUtils.replace(regExPat, "(.|\n)", ".");
				try {
					_acquireMatches(src, regExPat, matches,
							Perl5Compiler.SINGLELINE_MASK);
				} catch (StackOverflowError err2) {
					System.err
							.println("2nd StackOverflowError on _acquireMatches with REGEX->"
									+ regExPat);
					throw new IllegalStateException(err.getMessage());
				}
			}
		} catch (MalformedPatternException mpe) {
			throw new IllegalArgumentException(mpe.getMessage());
		}
	}

	private void _acquireMatches(String src, String regExPat,
			ArrayList matches, int mask) throws MalformedPatternException {
		Perl5Compiler compiler = new Perl5Compiler();
		Perl5Matcher matcher = new Perl5Matcher();
		Pattern pattern = compiler.compile(regExPat, mask);

		PatternMatcherInput input = new PatternMatcherInput(src);
		//	int offset = 0;
		//	int entryCntr = 0;
		//	while ( matcher.contains(input, pattern) ) {
		//	  org.apache.oro.text.regex.MatchResult result = matcher.getMatch();
		//	  int bRes = result.beginOffset(0);
		//	  int begin = bRes + offset;
		//	  int eRes = result.endOffset(0);
		//	  int end = eRes + offset;
		//	  String entry = result.toString();
		//
		//	  PatternMatcherUtils.MatchResult ret = new
		// PatternMatcherUtils.MatchResult( begin, end, entry );
		//	  matches.add( ret );
		//	  offset += eRes;
		//	  src = src.substring( eRes );
		//	  input = new PatternMatcherInput( src );
		//	  // matcher = new Perl5Matcher();
		//	}
		//System.out.println( "2.matches.size=" + matches.size() );

		while (matcher.contains(input, pattern)) {
			org.apache.oro.text.regex.MatchResult result = matcher.getMatch();
			PatternMatcherUtils.MatchResult ret = new PatternMatcherUtils.MatchResult(
					result.beginOffset(0), result.endOffset(0), result
							.toString());
			matches.add(ret);
		}
	}

	public boolean containsMatch(String src, String regExp)
			throws IllegalArgumentException, IllegalStateException {
		Perl5Compiler compiler = new Perl5Compiler();
		Perl5Matcher matcher = new Perl5Matcher();
		Pattern pattern = null;
		try {
			try {
				pattern = compiler
						.compile(regExp, Perl5Compiler.MULTILINE_MASK);
				return matcher.contains(src, pattern);
			} catch (StackOverflowError err) {
				regExp = StringUtils.replace(regExp, "(.|\n)", ".");
				try {
					pattern = compiler.compile(regExp,
							Perl5Compiler.SINGLELINE_MASK);
					return matcher.contains(src, pattern);
				} catch (StackOverflowError err2) {
					throw new IllegalStateException(err2.getMessage());
				}
			}
		} catch (MalformedPatternException mpe) {
			throw new IllegalArgumentException(mpe.getMessage());
		}
	}

	public PatternMatcherUtils.MatcherBundle createMatcherBundle(List regExps)
			throws IllegalArgumentException, IllegalStateException {
		try {
			OroBundle ret = new OroBundle(regExps);
			return ret;
		} catch (MalformedPatternException err) {
			throw new IllegalArgumentException(err.getMessage());
		}
	}

	static protected class OroBundle
			implements
				PatternMatcherUtils.MatcherBundle {
		private ArrayList expressions = new ArrayList();

		public OroBundle(List expStrs) throws MalformedPatternException {
			int max = expStrs.size();
			for (int cntr = 0; cntr < max; cntr++) {
				String regExpStr = (String) expStrs.get(cntr);
				expressions
						.add(new MultiThenSingleLinePatternMatcher(regExpStr));
			}
		}

		public boolean contains(String src) throws IllegalArgumentException,
				IllegalStateException {
			int max = expressions.size();
			Perl5Matcher matcher = new Perl5Matcher();
			for (int cntr = 0; cntr < max; cntr++) {
				MultiThenSingleLinePatternMatcher pat = (MultiThenSingleLinePatternMatcher) expressions
						.get(cntr);
				if (pat.contains(src, matcher))
					return true;
			}
			return false;
		}
	}

	static private class MultiThenSingleLinePatternMatcher {
		Pattern multiLine, singleLine;

		public MultiThenSingleLinePatternMatcher(String exp)
				throws MalformedPatternException {
			Perl5Compiler compiler = new Perl5Compiler();
			multiLine = compiler.compile(exp, Perl5Compiler.MULTILINE_MASK);
			exp = StringUtils.replace(exp, "(.|\n)", ".");
			singleLine = compiler.compile(exp, Perl5Compiler.SINGLELINE_MASK);
		}

		public boolean contains(String src, Perl5Matcher matcher) {
			try {
				return matcher.contains(src, multiLine);
			} catch (StackOverflowError err) {
				try {
					return matcher.contains(src, singleLine);
				} catch (StackOverflowError err2) {
					throw new IllegalStateException(err2.getMessage());
				}
			}
		}
	}
}